package com.tengju.bff.interfaces.manage.crm.user.facade;

import com.google.common.collect.Lists;
import com.tengju.bff.interfaces.manage.crm.user.assembler.UserAssembler;
import com.tengju.bff.interfaces.manage.crm.user.vo.*;
import com.tengju.bff.interfaces.shared.InterfaceCode;
import com.tengju.bff.interfaces.shared.InterfaceException;
import com.tengju.bff.interfaces.shared.servlet.ServletContextUtil;
import com.tengju.data.domain.model.user.DominationDetail;
import com.tengju.data.domain.model.user.DominationDetailRepository;
import com.tengju.data.domain.shared.DateUtil;
import com.tengju.user.application.archives.StarSignService;
import com.tengju.user.application.user.UserDocumentService;
import com.tengju.user.application.user.UserInfoService;
import com.tengju.user.application.user.dto.MobileManageChangeForm;
import com.tengju.user.application.user.dto.UserSearchForm;
import com.tengju.user.domain.model.doc.UserDocument;
import com.tengju.user.domain.model.club.Club;
import com.tengju.user.domain.model.club.ClubRepository;
import com.tengju.user.domain.model.login.UserAccount;
import com.tengju.user.domain.model.login.UserType;
import com.tengju.user.domain.model.sign.StarSignInfo;
import com.tengju.user.domain.model.sign.StarSignInfoRepository;
import com.tengju.user.domain.model.star.StarIndicator;
import com.tengju.user.domain.model.user.*;
import com.tengju.user.domain.service.RemoteUserService;
import com.tengju.user.domain.service.StarIndicatorStatService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class UserManageFacade {

    private final UserInfoRepository userInfoRepository;
    private final UserAccountRepository userAccountRepository;
    private final StarSignService starSignService;
    private final RemoteUserService abmUserService;
    private final StarSignInfoRepository starSignInfoRepository;
    private final UserInfoService userInfoService;
    private final ClubRepository clubRepository;
    private final StarIndicatorStatService starIndicatorStatExternalService;
    private final UserDocumentService userDocumentService;
    private final DominationDetailRepository dominationDetailRepository;

    @Transactional(value = "dealerTransactionManager", rollbackFor = Exception.class)
    public void changeMobile(MobileManageChangeForm form) throws InterfaceException {
        UserInfo userInfo = userInfoRepository.getByAreaCodeAndMobile(form.getOldAreaCode(), form.getOldMobile());
        UserAccount userAccount = userAccountRepository.queryUserAccount(form.getOldAreaCode() + form.getOldMobile(), UserType.USER);

        if (userInfo == null || userAccount == null) {
            throw new InterfaceException(InterfaceCode.USER_NOT_EXIST);
        }

        if (userInfo.getIdCode().getValue() != form.getIdCode()) {
            throw new InterfaceException(InterfaceCode.ID_CODE_MOBILE_NOT_MATCH);
        }

        userInfo.changeMobile(form.getNewAreaCode(), form.getNewMobile());
        userAccount.changeUsername(form.getNewAreaCode(), form.getNewMobile());

        userInfoRepository.updateAreaCodeAndMobile(userInfo);
        userAccountRepository.changeUsername(userAccount);
    }

    public PageUserVo queryUser(UserForm form) {

        PageUserVo pageUserVo = new PageUserVo();
        pageUserVo.setPageSize(form.getPageSize());
        pageUserVo.setPageIndex(form.getPageIndex());
        pageUserVo.setTotal(0);
        pageUserVo.setUserVos(Lists.newArrayList());

        List<UserIdCode> genSecIdCodes = ServletContextUtil.getServletContext().getGenSecIdCodes();
        if (CollectionUtils.isEmpty(genSecIdCodes)) {
            return pageUserVo;
        }
        UserSearchForm searchForm = UserAssembler.toSearchForm(form, genSecIdCodes);

        if (form.getDominationTeamPidCode() != null && form.getDominationTeamPidCode() > 0) {
            DominationDetail dominationDetail = dominationDetailRepository.getByIdCode(new com.tengju.data.domain.model.user.UserIdCode(form.getDominationTeamPidCode()));
            if (dominationDetail == null || DominationLevelEnum.DEALER == DominationLevelEnum.parseByVal(dominationDetail.getDominationLevel().getVal())) {
                return pageUserVo;
            }
            searchForm.belongOwner(dominationDetail.getDominationLevel(), new UserIdCode(form.getDominationTeamPidCode()));
        }

        if (form.isMonthNew()) {
            searchForm.setMonthNewStartTime(DateUtil.toLong(DateUtil.getFirstDayOfMonthMin()));
            searchForm.setMonthNewEndTime(DateUtil.toLong(LocalDateTime.now()));
        }

        Page<UserDocument> userDocuments = userDocumentService.search(searchForm);
        pageUserVo.setTotal((int) userDocuments.getTotalElements());

        if (!userDocuments.isEmpty()) {
            List<UserIdCode> pidCodes = userDocuments.stream()
                    .map(UserDocument::getParentIdCode)
                    .filter(idCode -> idCode != null && idCode > 0)
                    .map(UserIdCode::new).collect(Collectors.toList());
            List<UserInfo> pUserList = abmUserService.getByIdList(pidCodes);
            Map<UserIdCode, UserInfo> parentUserMap = pUserList.stream()
                    .collect(Collectors.toMap(UserInfo::getIdCode, Function.identity()));

            List<UserIdCode> idCodes = userDocuments.stream()
                    .map(UserDocument::getIdCode)
                    .filter(idCode -> idCode != null && idCode > 0)
                    .map(UserIdCode::new).collect(Collectors.toList());
            List<StarIndicator> starIndicatorList = starIndicatorStatExternalService.batchByIdCode(idCodes);
            //筛选不满足条件的指标
            starIndicatorList = starIndicatorList.stream()
                    .filter(v -> v.getIndicatorTargetValue().compareTo(BigDecimal.ZERO) >= 0)
                    .filter(v -> v.getIndicatorTargetValue().compareTo(v.getIndicatorValue()) > 0)
                    .collect(Collectors.toList());
            Map<UserIdCode, List<StarIndicator>> idCodeStarIndicatorMap = starIndicatorList.stream()
                    .collect(Collectors.groupingBy(StarIndicator::getIdCode));
            List<UserVo> userVoList = userDocuments.stream()
                    .map(userDocument -> UserAssembler.docToVo(userDocument, parentUserMap, idCodeStarIndicatorMap))
                    .collect(Collectors.toList());
            pageUserVo.setUserVos(userVoList);
        }
        return pageUserVo;
    }

    public UserDetailVO getDetail(UserIdCode idCode) {

        UserDetail userDetail = userInfoService.getUserDetail(idCode);
        if (userDetail == null){
            return null;
        }
        //俱乐部信息
        Club club = null;
        UserInfo clubFounder = null;
        if (userDetail.getBelongClubId() != null) {
            club = clubRepository.findById(userDetail.getBelongClubId());
            clubFounder = userInfoRepository.getByIdCode(club.getFounderIdCode());
        }
        //上级用户信息
        UserInfo parentUserInfo = userInfoService
                .getUserInfo(userDetail.getParentIdCode());
        //所属EC，SEC，EEC信息
        List<UserIdCode> idCodes = Lists.newArrayList();
        if (userDetail.getBelongEc() != null) {
            idCodes.add(userDetail.getBelongEc());
        }
        if (userDetail.getBelongSec() != null) {
            idCodes.add(userDetail.getBelongSec());
        }
        if (userDetail.getBelongEec() != null) {
            idCodes.add(userDetail.getBelongEec());
        }
        List<UserInfo> leaderUserInfos = userInfoRepository.batchGetUserInfo(idCodes);
        //最新签约流程信息
        StarSignInfo signInfo = starSignInfoRepository.getNewSignInfo(idCode);

        //最新升星记录
        StarChangeRecord lastChangeRecord = starSignService
                .getLastChangeRecord(idCode, userDetail.getStarLevel());

        return UserAssembler.modelToVo(userDetail, club, clubFounder,
                parentUserInfo, leaderUserInfos, signInfo, Optional.ofNullable(lastChangeRecord)
                        .map(StarChangeRecord::getChangeTime).orElse(null));
    }

    public StarIndicatorVO getStarIndicator(UserIdCode idCode) {

        List<StarIndicator> starIndicatorList = starIndicatorStatExternalService.getByIdCode(idCode);
        return UserAssembler.modelToVo(starIndicatorList);


    }

    public UserVo queryById(UserIdCode idCode) {
        UserSearchForm form = new UserSearchForm();
        form.setIdCode(idCode);
        Page<UserDocument> userDocuments = userDocumentService.search(form);
        if (!userDocuments.isEmpty()) {
            List<UserIdCode> pidCodes = userDocuments.stream()
                    .map(UserDocument::getParentIdCode)
                    .filter(userIdCode -> userIdCode != null && userIdCode > 0)
                    .map(UserIdCode::new).collect(Collectors.toList());
            List<UserInfo> pUserList = abmUserService.getByIdList(pidCodes);
            Map<UserIdCode, UserInfo> parentUserMap = pUserList.stream()
                    .collect(Collectors.toMap(UserInfo::getIdCode, Function.identity()));
            List<UserVo> userVoList = userDocuments.stream()
                    .map(userDocument -> UserAssembler.docToVo(userDocument, parentUserMap, new HashMap<>()))
                    .collect(Collectors.toList());
            return userVoList.get(0);
        }
        return null;
    }

    public List<UserVo> queryAllUser(UserForm form) {
        List<UserVo> userVos = Lists.newArrayList();

        List<UserIdCode> genSecIdCodes = ServletContextUtil.getServletContext().getGenSecIdCodes();
        if (CollectionUtils.isEmpty(genSecIdCodes)) {
            return userVos;
        }
        UserSearchForm searchForm = UserAssembler.toSearchForm(form, genSecIdCodes);

        if (form.getDominationTeamPidCode() != null && form.getDominationTeamPidCode() > 0) {
            DominationDetail dominationDetail = dominationDetailRepository.getByIdCode(new com.tengju.data.domain.model.user.UserIdCode(form.getDominationTeamPidCode()));
            if (dominationDetail == null) {
                return userVos;
            }
            searchForm.belongOwner(dominationDetail.getDominationLevel(), new UserIdCode(form.getDominationTeamPidCode()));
        }

        if (form.isMonthNew()) {
            searchForm.setMonthNewStartTime(DateUtil.toLong(DateUtil.getFirstDayOfMonthMin()));
            searchForm.setMonthNewEndTime(DateUtil.toLong(LocalDateTime.now()));
        }

        Page<UserDocument> userDocuments = userDocumentService.search(searchForm);

        if (!userDocuments.isEmpty()) {
            List<UserIdCode> pidCodes = userDocuments.stream()
                    .map(UserDocument::getParentIdCode)
                    .filter(idCode -> idCode != null && idCode > 0)
                    .map(UserIdCode::new).collect(Collectors.toList());
            List<UserInfo> pUserList = abmUserService.getByIdList(pidCodes);
            Map<UserIdCode, UserInfo> parentUserMap = pUserList.stream()
                    .collect(Collectors.toMap(UserInfo::getIdCode, Function.identity()));

            List<UserIdCode> idCodes = userDocuments.stream()
                    .map(UserDocument::getIdCode)
                    .filter(idCode -> idCode != null && idCode > 0)
                    .map(UserIdCode::new).collect(Collectors.toList());
            List<StarIndicator> starIndicatorList = starIndicatorStatExternalService.batchByIdCode(idCodes);
            //筛选不满足条件的指标
            starIndicatorList = starIndicatorList.stream()
                    .filter(v -> v.getIndicatorTargetValue().compareTo(BigDecimal.ZERO) >= 0)
                    .filter(v -> v.getIndicatorTargetValue().compareTo(v.getIndicatorValue()) > 0)
                    .collect(Collectors.toList());
            Map<UserIdCode, List<StarIndicator>> idCodeStarIndicatorMap = starIndicatorList.stream()
                    .collect(Collectors.groupingBy(StarIndicator::getIdCode));
            List<UserVo> userVoList = userDocuments.stream()
                    .map(userDocument -> UserAssembler.docToVo(userDocument, parentUserMap, idCodeStarIndicatorMap))
                    .collect(Collectors.toList());
//            pageUserVo.setUserVos(userVoList);
        }
        return userVos;
    }

}
